/**************************************************************************//**
 * @item     CosyOS-III Kernel
 * @file     os_taskmgr.c
 * @brief    任务管理器（Taskmgr）
 * @author   迟凯峰
 * @version  V1.2.2
 * @date     2025.04.15
 ******************************************************************************/

#include "os_var.h"
#if SYSCFG_DEBUGGING == __ENABLED__
#include "os_api.h"
#include "sv_com.h"
#include "sv_create.h"
#include "sv_task.h"
#include "ur_api.h"
#include <string.h>

/**
 \brief      字符串内存
 \details    字符串缓存 str[8] 的内存存储域。
 \note       对于 8051/251 来说，用户可自定义该内存，以寻求在性能和资源之间取得平衡。
             该内存默认被定义为 _SYS_MEM_，即 DATA 存储区，以实现高性能。
 */
#define _STR_MEM_ _SYS_MEM_

static char _STR_MEM_ str[8]; /*!< 字符串缓存 */
static char _XDATA_MEM_ * _SYS_MEM_ mptr; /*!< 指向任务管理器发送缓存的可移动指针 */

/**
 \brief      字符拷贝
 \param[in]  c         字符
 \return     无
 */
#define _chrcpy_(c) *mptr++ = c

/**
 \brief      字符n拷贝
 \param[in]  c         字符
 \param[in]  n         字符的数量
 \return     无
 */
static void _chrncpy_(const char c, s_u8_t n)
{
	do{
		*mptr++ = c;
	}while(--n);
}

/**
 \brief      空格拷贝
 \param[in]  n         空格的数量
 \return     无
 */
static void _spccpy_(s_u8_t n)
{
	do{
		*mptr++ = ' ';
	}while(--n);
}

/**
 \brief      字符串拷贝
 \param[in]  s         字符串指针
 \return     无
 */
static void _strcpy_(const char *s)
{
	while(*s){
		*mptr++ = *s++;
	}
}

/**
 \brief      字符串长度
 \param[in]  s         字符串指针
 \return     字符串长度
 */
static s_u8_t _strlen_(const char *s)
{
	s_u8_t i = 0;
	while(*s++){
		i++;
	}
	return i;
}

/**
 \brief      u8转字符串
 \param[in]  var       u8型数据
 \return     无
 */
static void _u8str_(const s_u8_t var)
{
	char _STR_MEM_ *ptr = str;
	if(var >= 100){
		*ptr++ = var / 100 + '0';
		goto Lable_2;
	}
	if(var >= 10){
		*ptr++ = var / 10 + '0';
		goto Lable_1;
	}
	else{
		*ptr++ = var /**/+ '0';
		goto Lable_0;
	}
	Lable_2: *ptr++ = (var % 100) / 10 + '0';
	Lable_1: *ptr++ = (var % 10) /**/+ '0';
	Lable_0: *ptr = '\0';
}

/**
 \brief      u16转字符串
 \param[in]  var       u16型数据
 \return     无
 */
static void _u16str_(const s_u16_t var)
{
	char _STR_MEM_ *ptr = str;
	if(var >= 10000){
		*ptr++ = var / 10000 + '0';
		goto Lable_4;
	}
	if(var >= 1000){
		*ptr++ = var / 1000 + '0';
		goto Lable_3;
	}
	if(var >= 100){
		*ptr++ = var / 100 + '0';
		goto Lable_2;
	}
	if(var >= 10){
		*ptr++ = var / 10 + '0';
		goto Lable_1;
	}
	else{
		*ptr++ = var /**/+ '0';
		goto Lable_0;
	}
	Lable_4: *ptr++ = (var % 10000) / 1000 + '0';
	Lable_3: *ptr++ = (var % 1000) / 100 + '0';
	Lable_2: *ptr++ = (var % 100) / 10 + '0';
	Lable_1: *ptr++ = (var % 10) /**/+ '0';
	Lable_0: *ptr = '\0';
}

/**
 \brief      u16长度
 \param[in]  var       u16型数据
 \return     长度
 */
static s_u8_t _u16len_(const s_u16_t var)
{
	if(var >= 10000) return 5;
	if(var >= 1000) return 4;
	if(var >= 100) return 3;
	if(var >= 10) return 2;
	return 1;
}

/**
 \brief      cpu使用率
 \param[in]  num       分子（分母：10000）
 \return     无
 */
static void _used_ratio_(const s_u16_t num)
{
	s_u8_t i;
	if(!num){
		str[0] = '0';
		str[1] = '\0';
		i = 2;
	}
	else{
		_u16str_(num);
		i = _strlen_(str);
		if(i > 2){
			str[i-0] = str[i-1];
			str[i-1] = str[i-2];
			str[i-2] = '.';
			str[i+1] = '\0';
			i += 2;
		}
		else{
			if(i == 1){
				str[2] = '0';
				str[3] = str[0];
			}
			else{
				str[2] = str[0];
				str[3] = str[1];
			}
			str[0] = '0';
			str[1] = '.';
			str[4] = '\0';
			i = 5;
		}
	}
	_spccpy_((s_u8_t)(OS_TASKMGR_LEN_CPU - i));
	_strcpy_(str);
	_chrcpy_('%');
}

#if SYSCFG_TASKPC_MONITOR == __ENABLED__
/**
 \brief      u8转十六进制字符串
 \param[in]  var       u8型数据
 \return     无
 \note       用于输出任务PC，十六进制字母为大写。
 */
static void _u8str16_(const s_u8_t var)
{
	str[0] = (var >> 4) + '0';
	str[1] = (var & 0x0F) + '0';
	if(str[0] > '9') str[0] += 0x07;
	if(str[1] > '9') str[1] += 0x07;
	*mptr++ = str[0];
	*mptr++ = str[1];
}
#endif

#define _taskname "\xC8\xCE\xCE\xF1\xB9\xDC\xC0\xED\xC6\xF7" /*!< "任务管理器" */
uCreateTask_TimQry
(
	OS_TMID_TASKMGR, s_sign_taskmgr, true,
	Taskmgr, SYSCFG_TASKPRIORITY - 2, SYSCFG_STACKSIZE_TASKMGR, 0, _taskname
)
{
	static char _XDATA_MEM_ *p[2];
	mptr = s_taskmgr_sendbuff;
	/* 标题1 */
	_strcpy_("\xC8\xCE\xCE\xF1\xB9\xDC\xC0\xED\xC6\xF7"); /*!< "任务管理器" */
	_spccpy_(OS_TASKMGR_LEN_LINE - OS_TASKMGR_LEN_CPU - OS_TASKMGR_LEN_RAM - 10);
	p[0] = mptr; /*!< 缓存CPU总使用率开始指针 */
	_spccpy_(OS_TASKMGR_LEN_CPU + OS_TASKMGR_LEN_RAM - 8);
	_strcpy_("CosyOS-3");
	_strcpy_("\r\n");
	/* 标题2 */
	_strcpy_("\xC3\xFB\xB3\xC6");         /*!< "名称" */
	_spccpy_(SYSCFG_TASKNAMELEN_MAX - 4);
	_strcpy_("\xD3\xC5\xCF\xC8\xBC\xB6"); /*!< "优先级" */
	_spccpy_(OS_TASKMGR_LEN_STA - 4);
	_strcpy_("\xD7\xB4\xCC\xAC");         /*!< "状态" */
	_spccpy_(OS_TASKMGR_LEN_CPU - 3);
	_strcpy_("CPU");                      /*!< "CPU" */
	_spccpy_(OS_TASKMGR_LEN_RAM - 4);
	_strcpy_("\xC4\xDA\xB4\xE6");         /*!< "内存" */
	_strcpy_("\r\n");
	/* - */
	_chrncpy_('-', OS_TASKMGR_LEN_LINE);
	_strcpy_("\r\n");
	/* 正文 */
	p[1] = mptr; /*!< 缓存正文开始指针 */
	while(true){
		static s_timqry_t upspeed = (SYSCFG_TASKMGR_UPSPEED * 1000UL) / SYSCFG_SYSTICK_CYCLE;
		static s_tasknode_ts node_temp;
		s_tasknode_tsp    node_curr;
		s_u16_t           numerator1 = 10000;
		s_u8_t            i = SYSCFG_TASKPRIORITY;
		#if SYSCFG_TASKPC_MONITOR == __ENABLED__
		m_pc_t            pc = s_pc;
		#endif
		mptr = p[1];
		
		__TASKQUE_NEXT:
		do{
			node_curr = s_task_queue[--i];
		}while(node_curr == OS_NULL);
		while(true){
			s_u16_t numerator2;
			mSysIRQ_Disable();
			s_memcpy(&node_temp, node_curr, sizeof(s_tasknode_ts));
			node_curr->usedtime[0] = 0;
			node_curr->usedtime[1] = 0;
			mSysIRQ_Enable();
			/* 名称 */
			_strcpy_(node_temp.name);
			if(SYSCFG_TASKNAMELEN_MAX > _strlen_(node_temp.name)){
				_spccpy_((s_u8_t)(SYSCFG_TASKNAMELEN_MAX - _strlen_(node_temp.name)));
			}
			/* 优先级 */
			_u8str_ (node_temp.pri);
			_spccpy_((s_u8_t)(OS_TASKMGR_LEN_PRI - _strlen_(str)));
			_strcpy_(str);
			/* 状态 */
			if(node_temp.status == OS_STATUS_READY){
				_spccpy_(OS_TASKMGR_LEN_STA);
			}
			else if(node_temp.status == OS_STATUS_BLOCKED){
				_spccpy_(OS_TASKMGR_LEN_STA - 3);
				switch(node_temp.blocktype){
				case OS_BLOCKED_DELAY:     _strcpy_("dly"); break;
				case OS_BLOCKED_BINARY:    _strcpy_("bin"); break;
				case OS_BLOCKED_MUTEX:     _strcpy_("mut"); break;
				case OS_BLOCKED_SEMAPHORE: _strcpy_("sem"); break;
				case OS_BLOCKED_FETION:    _strcpy_("fet"); break;
				case OS_BLOCKED_MAIL:      _strcpy_("mal"); break;
				case OS_BLOCKED_MSG:       _strcpy_("msg"); break;
				case 1: _strcpy_("gro"); break;
				case 2: _strcpy_("gro"); break;
				case 4: _strcpy_("gro"); break;
				}
			}
			else{
				_spccpy_(OS_TASKMGR_LEN_STA - 1);
				if(node_temp.status == OS_STATUS_TIMEOUT){
					_chrcpy_('O');
				}
				else if(node_temp.status & OS_STATUS_SUSPENDED){
					_chrcpy_('^');
				}
				else if(node_temp.status == OS_STATUS_STOPPED){
					_chrcpy_('!');
				}
				else{
					_chrcpy_('X');
				}
			}
			/* CPU */
			numerator2 = (
			    ((node_temp.usedtime[0] * 10000UL) / upspeed)
			  + ((node_temp.usedtime[1] * 10000UL) / upspeed / MCUCFG_SYSTICK_COUNT1CYC)
			);
			_used_ratio_(numerator2);
			if(!node_temp.pri){
				numerator1 -= numerator2;
			}
			/* 内存 */
			_spccpy_(
				(s_u8_t)(
				    OS_TASKMGR_LEN_RAM - 4
				  - _u16len_((s_u16_t)node_temp.stacklen_max)
				  - _u16len_((s_u16_t)node_temp.stacksize)
				)
			);
			_u16str_(node_temp.stacklen_max);
			_strcpy_(str);
			_strcpy_("B/");
			switch(node_temp.create){
			case 0: _chrcpy_('s'); break;
			case 1: _chrcpy_('m'); break;
			case 2: _chrcpy_('r'); break;
			}
			_u16str_(node_temp.stacksize);
			_strcpy_(str);
			_chrcpy_('B');
			_strcpy_("\r\n");
			/* 下一任务 */
			#if SYSCFG_SAMEPRISCHEDULE
			if(node_curr == s_task_queue[i]->last){
				if(!i) break;
				goto __TASKQUE_NEXT;
			}
			else{
				node_curr = node_temp.next;
			}
			#else
			if(true){
				if(!i) break;
				goto __TASKQUE_NEXT;
			}
			#endif
		}
		/* CPU总使用率 */
		if(true){
			char _XDATA_MEM_ *p0 = mptr;
			mptr = p[0];
			_used_ratio_(numerator1);
			mptr = p0;
		}
		
		_strcpy_("\r\n"); /*!< null-line */
		/* PSV-FIFO */
		_strcpy_("PSV-FIFO: ");
		#if SYSCFG_PENDSVFIFO_MONITOR == __ENABLED__
		if(mPendSV_FIFO_DepthMAX > MCUCFG_PENDSVFIFO_DEPTH){
			s_fault.overflow_pendsvfifo = true;
		}
		_u16str_(mPendSV_FIFO_DepthMAX);
		_strcpy_(str);
		_strcpy_("/");
		_u16str_(MCUCFG_PENDSVFIFO_DEPTH);
		_strcpy_(str);
		_spccpy_(
			(s_u8_t)(
			    OS_TASKMGR_LEN_LINE - 20 - 10 - 1
			  - _u16len_((s_u16_t)mPendSV_FIFO_DepthMAX)
			  - _u16len_((s_u16_t)MCUCFG_PENDSVFIFO_DEPTH)
			)
		);
		#else
		_strcpy_("null");
		_spccpy_(OS_TASKMGR_LEN_LINE - 20 - 10 - 4);
		#endif
		_strcpy_("| ");
		/* 任务pc值 */
		_strcpy_("\xC8\xCE\xCE\xF1pc\xD6\xB5: ");
		#if SYSCFG_TASKPC_MONITOR == __ENABLED__
		#if MCUCFG_PCLEN > 2
		_u8str16_((s_u8_t)(pc >> 24));
		_u8str16_((s_u8_t)(pc >> 16));
		#endif
		_u8str16_((s_u8_t)(pc >> 8));
		_u8str16_((s_u8_t)(pc));
		#else
		_strcpy_("null");
		#endif
		_strcpy_("\r\n");
		/* 运行时间 */
		_strcpy_("\xD4\xCB\xD0\xD0\xCA\xB1\xBC\xE4: ");
		#if SYSCFG_RUNTIME_COUNT == __ENABLED__
		if(true){
			s_runtime_ts runtime;
			mSysIRQ_Disable();
			runtime = s_runtime;
			mSysIRQ_Enable();
			_u16str_(runtime.day);
			_strcpy_(str);
			_chrcpy_('-');
			if(runtime.hour < 10) _chrcpy_('0');
			_u8str_(runtime.hour);
			_strcpy_(str);
			_chrcpy_(':');
			if(runtime.minute < 10) _chrcpy_('0');
			_u8str_(runtime.minute);
			_strcpy_(str);
			_chrcpy_(':');
			if(runtime.second < 10) _chrcpy_('0');
			_u8str_(runtime.second);
			_strcpy_(str);
			_spccpy_((s_u8_t)(OS_TASKMGR_LEN_LINE - 20 - 10 - 9 - _u16len_(runtime.day)));
		}
		#else
		_strcpy_("null");
		_spccpy_(OS_TASKMGR_LEN_LINE - 20 - 10 - 4);
		#endif
		_strcpy_("| ");
		/* 滴答时间 */
		_strcpy_("\xB5\xCE\xB4\xF0\xCA\xB1\xBC\xE4: ");
		#if SYSCFG_SYSTICKTIME_COUNT == __ENABLED__
		mSysIRQ_Disable();
		if(s_tick_count2){
			s_u32_t counter1 = s_tick_count1;
			s_u32_t counter2 = s_tick_count2;
			s_tick_count1 = 0;
			s_tick_count2 = 0;
			mSysIRQ_Enable();
			counter2 = (counter1 * 100) / counter2;
			#if defined(MCUCFG_SYSCLK) && defined(MCUCFG_SYSTICK_CLKDIV) \
			 && (MCUCFG_SYSCLK > 0) && (MCUCFG_SYSTICK_CLKDIV > 0)
			counter2 = (counter2 * MCUCFG_SYSTICK_CLKDIV) / MCUCFG_SYSCLK;
			#elif defined(MCUCFG_SYSTICK_CLK) && (MCUCFG_SYSTICK_CLK > 0)
			counter2 =  counter2 / MCUCFG_SYSTICK_CLK;
			#else
			#error SysTick CLK undefined!
			#endif
			_u16str_((s_u16_t)(counter2 / 100));
			_strcpy_(str);
			_chrcpy_('.');
			_u8str_((s_u8_t)((counter2 % 100) / 10));
			_strcpy_(str);
			_u8str_((s_u8_t)(counter2 % 10));
			_strcpy_(str);
			_strcpy_("us");
		}
		else{
			mSysIRQ_Enable();
		}
		#else
		_strcpy_("null");
		#endif
		_strcpy_("\r\n");
		/* 系统警告 */
		_strcpy_("\xCF\xB5\xCD\xB3\xBE\xAF\xB8\xE6: ");
		if(*(s_u8_t *)&s_alarm){
			if(s_alarm.overflow_msgqueue){
				_strcpy_("omq, ");
			}
			if(s_alarm.timeout_saferuntime){
				_strcpy_("srt, ");
			}
			if(s_alarm.outrange_taskpriority){
				_strcpy_("otp, ");
			}
			if(s_alarm.realloc_taskstack){
				_strcpy_("rts, ");
			}
			if(s_alarm.overflow_taskstack){
				_strcpy_("ots, ");
			}
			mptr -= 2;
		}
		else{
			_strcpy_("\xCE\xDE");
		}
		_strcpy_("\r\n");
		/* 系统异常 */
		_strcpy_("\xCF\xB5\xCD\xB3\xD2\xEC\xB3\xA3: ");
		if(*(s_u8_t *)&s_fault){
			if(s_fault.mallocfailed_msgnode){
				_strcpy_("mmn, ");
			}
			if(s_fault.mallocfailed_tasknode){
				_strcpy_("mtn, ");
			}
			if(s_fault.mallocfailed_taskstack){
				_strcpy_("mts, ");
			}
			if(s_fault.reallocfailed_taskstack){
				_strcpy_("rts, ");
			}
			if(s_fault.overflow_taskstack){
				_strcpy_("ots, ");
			}
			if(s_fault.failed_startuptask){
				_strcpy_("fst, ");
			}
			if(s_fault.error_recvmsg_int){
				_strcpy_("erm, ");
			}
			#if SYSCFG_PENDSVFIFO_MONITOR == __ENABLED__
			if(s_fault.overflow_pendsvfifo){
				_strcpy_("opd, ");
			}
			#endif
			mptr -= 2;
		}
		else{
			_strcpy_("\xCE\xDE");
		}
		_strcpy_("\r\n");
		/* 当前时间 */
		#if SYSCFG_RTC_SHOW == __ENABLED__
		if(true){
			s_rtc_ts rtc;
			mSysIRQ_Disable();
			rtc = s_rtc;
			mSysIRQ_Enable();
			_spccpy_(OS_TASKMGR_LEN_LINE - 24);
			_u8str_(rtc.yeah);
			_strcpy_(str);
			if(rtc.year < 10) _chrcpy_('0');
			_u8str_(rtc.year);
			_strcpy_(str);
			_chrcpy_('.');
			if(rtc.month < 10) _chrcpy_('0');
			_u8str_(rtc.month);
			_strcpy_(str);
			_chrcpy_('.');
			if(rtc.date < 10) _chrcpy_('0');
			_u8str_(rtc.date);
			_strcpy_(str);
			_chrcpy_('-');
			if(rtc.hour < 10) _chrcpy_('0');
			_u8str_(rtc.hour);
			_strcpy_(str);
			_chrcpy_(':');
			if(rtc.minute < 10) _chrcpy_('0');
			_u8str_(rtc.minute);
			_strcpy_(str);
			_chrcpy_(':');
			if(rtc.second < 10) _chrcpy_('0');
			_u8str_(rtc.second);
			_strcpy_(str);
			_chrcpy_(' ');
			_strcpy_("\xD6\xDC");
			switch(rtc.day){
			case 1: _strcpy_("\xD2\xBB"); break;
			case 2: _strcpy_("\xB6\xFE"); break;
			case 3: _strcpy_("\xC8\xFD"); break;
			case 4: _strcpy_("\xCB\xC4"); break;
			case 5: _strcpy_("\xCE\xE5"); break;
			case 6: _strcpy_("\xC1\xF9"); break;
			case 7: _strcpy_("\xC8\xD5"); break;
			}
			_strcpy_("\r\n");
		}
		#endif
		
		_strcpy_("\r\n"); /*!< null-line */
		_chrcpy_('\0'); /*!< string-tail */
		/* - */
		mSysIRQ_Disable();
		upspeed = s_timqry_handle[OS_TMID_TASKMGR]->reload;
		s_debug_sendtype |= OS_DEBUG_SEND_TASKMGR;
		#if SYSCFG_DEBUG_SENDLEN == __ENABLED__
		s_taskmgr_sendlen = (size_t)(mptr - s_taskmgr_sendbuff - 1);
		#endif
		sv_suspend_task(s_task_current);
		su_kernel_unlock0_psv();
	}
}
#undef _taskname

#endif
